﻿#region Copyright (c) 2012-11, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

#if TESTS

using System;
using NUnit.Framework;


namespace Amarok.Agents
{
	[TestFixture]
	public class Test_Operation
	{
		[Serializable]
		public class MyOperation : Operation
		{
			public Int32 Value
			{
				get;
				private set;
			}

			public MyOperation(Int32 value)
			{
				this.Value = value;
			}
		}


		// --- TESTS ---


		[Test]
		public void Test_Construction()
		{
			var operation = new MyOperation(123);

			Assert.That(operation.Value, Is.EqualTo(123));
			Assert.That(operation.Id, Is.Not.EqualTo(Guid.Empty));
			Assert.That(operation.Label, Is.Null);
			Assert.That(operation.HasLabel, Is.False);
			Assert.That(operation.ToString(), Is.StringContaining("Amarok.Agents.Test_Operation+MyOperation("));
			Assert.That(operation.ToString(), Is.StringContaining("Id: "));
			Assert.That(operation.ToString(), Is.StringContaining(", Label: <null>)"));
			Assert.That(operation.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.False);
		}

		[Test]
		public void Test_Cancel()
		{
			var operation = new MyOperation(123);

			Assert.That(operation.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.False);

			operation.Cancel();

			Assert.That(operation.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.True);
		}

		[Test]
		public void Test_Cancel_Twice()
		{
			var operation = new MyOperation(123);

			operation.Cancel();
			operation.Cancel();

			Assert.That(operation.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation.CancellationToken.IsCancellationRequested, Is.True);
		}

		[Test]
		public void Test_Cancel_After_Dispose()
		{
			var operation = new MyOperation(123);

			Helper.Dispose(operation);

			Assert.Throws<ObjectDisposedException>(() =>
				{
					operation.Cancel();
				});
		}

		[Test]
		public void Test_CancellationToken_After_Dispose()
		{
			var operation = new MyOperation(123);

			Helper.Dispose(operation);

			Assert.Throws<ObjectDisposedException>(() =>
				{
					var token = operation.CancellationToken;
				});
		}

		[Test]
		public void Test_Acquire()
		{
			var operation = new MyOperation(123);

			operation.Acquire();

			Assert.Throws<InvalidOperationException>(() =>
				{
					operation.Acquire();
				});

			Assert.Throws<InvalidOperationException>(() =>
				{
					operation.Acquire();
				});
		}

		[Test]
		public void Test_TryAcquire()
		{
			var operation = new MyOperation(123);

			Assert.That(operation.TryAcquire(), Is.True);
			Assert.That(operation.TryAcquire(), Is.False);
			Assert.That(operation.TryAcquire(), Is.False);
		}

		[Test]
		public void Test_Acquire_Serialization_BinaryFormatter()
		{
			var operation1 = new MyOperation(123);
			operation1.Acquire();
			var operation2 = TestHelper.TestBinaryFormatterRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			operation2.Acquire();
		}

		[Test]
		public void Test_Acquire_Serialization_DataContract()
		{
			var operation1 = new MyOperation(123);
			operation1.Acquire();
			var operation2 = TestHelper.TestDataContractRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			operation2.Acquire();
		}

		[Test]
		public void Test_Serialization_BinaryFormatter_WithoutLabel()
		{
			var operation1 = new MyOperation(123);
			var operation2 = TestHelper.TestBinaryFormatterRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation1.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation2.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));
		}

		[Test]
		public void Test_Serialization_BinaryFormatter_WithLabel()
		{
			var operation1 = new MyOperation(123);
			operation1.Label = "COM1";
			var operation2 = TestHelper.TestBinaryFormatterRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation1.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation2.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));
		}

		[Test]
		public void Test_Serialization_DataContract_WithoutLabel()
		{
			var operation1 = new MyOperation(123);
			var operation2 = TestHelper.TestDataContractRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation1.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation2.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.Null);
			Assert.That(operation2.HasLabel, Is.False);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));
		}

		[Test]
		public void Test_Serialization_DataContract_WithLabel()
		{
			var operation1 = new MyOperation(123);
			operation1.Label = "COM1";
			var operation2 = TestHelper.TestDataContractRoundtrip(operation1);

			Assert.That(operation2, Is.Not.SameAs(operation1));

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation1.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.False);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));

			operation2.Cancel();

			Assert.That(operation1.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation1.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.CancellationToken.CanBeCanceled, Is.True);
			Assert.That(operation2.CancellationToken.IsCancellationRequested, Is.True);
			Assert.That(operation2.Value, Is.EqualTo(123));
			Assert.That(operation2.Label, Is.EqualTo("COM1"));
			Assert.That(operation2.HasLabel, Is.True);
			Assert.That(operation2.Id, Is.EqualTo(operation1.Id));
		}

	}
}

#endif
